package cn.toguide.ffmpeg.component;

import cn.toguide.ffmpeg.config.FFMpegSDKProperties;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.exec.*;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.util.Map;

@Slf4j
@Component
public class CommandManager {
    @Resource
    private FFMpegSDKProperties ffmpegCommandProperties;
    public String getCommand(String commandName) {
        Map<String, String> commands = ffmpegCommandProperties.getCommands();
        if (commands != null) {
            String command = commands.get(commandName);
            if (command != null) {
                log.debug("{} -> {}", commandName, command);
                return command;
            }
        }
        return "";
    }

    public String activeCommand(String command, String inputPath, String outputPath) {
        return command.replace(FFMpegSDKProperties.INPUT_FILE_REPLACE_KEY, inputPath)
                .replace(FFMpegSDKProperties.OUTPUT_FILE_REPLACE_KEY, outputPath);
    }

    public void exec(String command) {
        log.info("exec command: {}", command);
        ByteArrayOutputStream susStream = new ByteArrayOutputStream();
        ByteArrayOutputStream errStream = new ByteArrayOutputStream();
        CommandLine commandLine = CommandLine.parse(command);
        DefaultExecutor exec = new DefaultExecutor();
        ExecuteWatchdog watchdog = new ExecuteWatchdog(5 * 60 * 1000);
        exec.setWatchdog(watchdog);
        PumpStreamHandler streamHandler = new PumpStreamHandler(susStream, errStream);
        exec.setStreamHandler(streamHandler);
        try {
            StopWatch stopWatch = new StopWatch();
            stopWatch.start();
            int code = exec.execute(commandLine);
            log.debug("command exec result code: {}", code);
            stopWatch.stop();
            log.debug("command cost time：" + stopWatch.getTotalTimeSeconds() + "s");
        } catch (ExecuteException | UnsupportedEncodingException e) {
            log.error(e.toString());
            if (watchdog.killedProcess()) {
                log.error("command time out: {}", command);
            }
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        } finally {
            // 不同操作系统注意编码，否则结果乱码
            String suc;
            String err;
            suc = susStream.toString(StandardCharsets.UTF_8);
            err = errStream.toString(StandardCharsets.UTF_8);
            if (!err.isEmpty()) {
                log.info(err);
            }
            if (!suc.isEmpty()) {
                log.info(suc);
            }
        }
    }

    public String execR(String command) {
        log.info("exec command: {}", command);
        ByteArrayOutputStream susStream = new ByteArrayOutputStream();
        ByteArrayOutputStream errStream = new ByteArrayOutputStream();
        CommandLine commandLine = CommandLine.parse(command);
        DefaultExecutor exec = new DefaultExecutor();
        ExecuteWatchdog watchdog = new ExecuteWatchdog(5 * 60 * 1000);
        exec.setWatchdog(watchdog);
        PumpStreamHandler streamHandler = new PumpStreamHandler(susStream, errStream);
        exec.setStreamHandler(streamHandler);
        String res = "";
        try {
            StopWatch stopWatch = new StopWatch();
            stopWatch.start();
            int code = exec.execute(commandLine);
            log.debug("command exec result code: {}", code);
            stopWatch.stop();
            log.debug("command cost time：" + stopWatch.getTotalTimeSeconds() + "s");

            // 不同操作系统注意编码，否则结果乱码
            String suc;
            String err;
            suc = susStream.toString(StandardCharsets.UTF_8);
            err = errStream.toString(StandardCharsets.UTF_8);
            if (!err.isEmpty()) {
                log.info(err);
            }
            if (!suc.isEmpty()) {
                log.info(suc);
                return suc;
            }

        } catch (ExecuteException | UnsupportedEncodingException e) {
            log.error(e.toString());
            if (watchdog.killedProcess()) {
                log.error("command time out: {}", command);
            }
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
        return "0";
    }
}
